home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Experimental BBS Explossion 3
/
Experimental BBS Explossion III.iso
/
disk
/
ocop.zip
/
OCOP.CPP
next >
Wrap
C/C++ Source or Header
|
1993-01-11
|
26KB
|
635 lines
/*
OCOP.CPP: a diskette copy optimizer
-------------------------------------
Garry J. Vass
Gundhof Str 18
D6000 Frankfurt 71
Germany
It is not easy to explain why this utility exists. In 1986,
I was travelling all over the globe with diskettes. Sometimes
I arrived at some place only to learn that my diskettes were
faulty - somewhat embarrassing to say the least. So I wrote
a small assembler program called OPTCOPY.COM, that copied files
and read them back 10 times. Reliability went up, but I was
bothered because I was carrying too many diskettes. I wanted
reliability and optimization.
In 1988, I wrote SAFECOPY.COM. With this I was satisfied, and
it worked well for almost 5 years. Some of my Sysop buddies had
been using OPTCOPY and naturally wanted the upgrade, so I passed
it around. I even uploaded it to Compuserve and it was still
there in 1993. Those were the days of DOS 2.1, and being the
cautious sort, I included a hook that stopped the program from
running if it encountered anything higher than DOS 3.X (who could
imagine something beyond DOS 3?).
To my astonishment, DOS survived into DOS 5. To my further
astonishmment, SAFECOPY had managed to find itself a secure
niche of users who bitched and wanted a DOS 5 version.
So here is OCOP. It is not great software. It is simply
a utility that somebody like NORTON or CENTRAL POINT should
have done in a flashy way. Oh, by the way, it is called
OCOP (not OCOPY) because of the differences between German
and American keyboards.
Times change, in these days of virus-infested media, a utility
of this sort demands source. The source lies below.
If you use this program, keep the source safe because I
do not plan on issuing upgrades. It works for me.
Rights. I abandon all rights and all responsibility
associated with this product.
The source compiles under Borland 3.1 with the command
line bcc -ml ocop.cpp.
*/
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
#include <stdio.h> // some basic rtl includes
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
#include <dir.h>
#include <dos.h>
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
typedef struct sFI { // your basic heap administration
struct find_t blk; // structure
char dirof[ 128 ];
int status[ 2 ];
struct sFI *next;
}sfxxx;
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
struct sFI *Rootdirs = NULL; // some global variables
struct sFI *Rootfiles = NULL;
char Cmd[ 200 ];
char Basecwd[ 128 ];
char Spec[ 128 ];
long Total;
int Flag_subdirs = 0;
int Flag_usezip = 0;
char Argv1[ 50 ];
char Argv2[ 50 ];
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
void drain( void ) // clear the keyboard buffer
{
while( kbhit() )
getch();
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
void hitakey( void ) // take a bold guess what this does...
{
printf( "\n\n\n ----->Hit a key..." );
getch();
drain();
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int removedoubles( char *s ) // the lazy programmer's method
{ // for getting path names correct
if( !strlen( s ) ) return( 0 );
char *p = strstr( s, "\\\\" );
while( p ) {
strcpy( p, p + 1 );
removedoubles( s );
p = strstr( s, "\\\\" );
}
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int insertdirlist( char *s, struct find_t *b ) // stuff a directory
{
struct sFI *n;
n = (struct sFI *)malloc( sizeof( struct sFI ) );
if( n ) {
memmove( &n -> blk, b, sizeof( struct find_t ) );
strcpy( n -> dirof, s );
memset( n -> status, 0, 4 * sizeof( int ) );
n -> next = NULL;
if( !Rootdirs ) {
Rootdirs = n;
} else {
n -> next = Rootdirs;
Rootdirs = n;
}
return( 1 );
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int insertfilelist( char *s, struct find_t *b ) // stuff a file
{
struct sFI *n;
n = (struct sFI *)malloc( sizeof( struct sFI ) );
if( n ) {
memmove( &n -> blk, b, sizeof( struct find_t ) );
removedoubles( s );
strcpy( n -> dirof, s );
memset( n -> status, 0, 4 * sizeof( int ) );
n -> next = NULL;
if( !Rootfiles ) {
Rootfiles = n;
} else {
if( n -> blk.size > Rootfiles -> blk.size ) {
n -> next = Rootfiles;
Rootfiles = n;
} else {
struct sFI *p = Rootfiles;
for( struct sFI *i = Rootfiles; i; i = i -> next ) {
if( n -> blk.size > i -> blk.size ) {
n -> next = i;
p -> next = n;
return( 1 );
}
if( !i -> next ) {
i -> next = n;
return( 1 );
}
p = i;
}
}
}
return( 1 );
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int walkcopied( void ) // stroll down the list of copied files
{
int ret = 0;
for( struct sFI *i = Rootfiles; i; i = i -> next ) {
if( i -> status[ 0 ] ) {
printf( "%s\\%s %ld ...copied....\n", i -> dirof, i -> blk.name, i -> blk.size );
drain();
}
}
return( ret );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int walknotcopied( void ) // stroll down the list of files yet to come.
{
int ret = 0;
for( struct sFI *i = Rootfiles; i; i = i -> next ) {
if( !i -> status[ 0 ] ) {
printf( "%s\\%s %ld ...not copied....\n", i -> dirof, i -> blk.name, i -> blk.size );
printf( "\ta. next file\n" );
printf( "\tb. forget about this file - skip it\n" );
printf( "\tc. exit the walker\n" );
drain();
char c = toupper( getch() );
switch( c ) {
case 'B':
i -> status[ 0 ] = 2;
break;
case 'C':
return( ret );
}
}
}
return( ret );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int walkdriver( void ) // manage the strolling process
{
int ret = 0;
walktop:
clrscr();
printf( "a. Walk files that have been copied\n" );
printf( "b. Walk files not yet copied\n" );
printf( "q. Leave the walker\n" );
drain();
ret = toupper( getch() );
switch( ret ) {
case 'A':
walkcopied();
goto walktop;
case 'B':
walknotcopied();
goto walktop;
case 'Q':
return( 1 );
default:
goto walktop;
}
return( ret );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int more( long *total ) // anything else to do?
{
int ret = 0;
*total = 0L;
for( struct sFI *i = Rootfiles; i; i = i -> next ) {
if( !i -> status[ 0 ] ) {
++ret;
*total += i -> blk.size;
}
}
return( ret );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
struct sFI *select( long m ) // find a file of length less than "m"
{
for( struct sFI *i = Rootfiles; i; i = i -> next ) {
if( i -> blk.size < m && i -> status[ 0 ] == 0 ) {
return( i );
}
}
return( NULL );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int builddirlist( char *p, char *s ) // build a heap of directories
{
char temp[ 128 ];
struct find_t blk;
int done;
strcpy( temp, p );
sprintf( Spec, "%s\\%s", temp, s );
removedoubles( Spec );
done = _dos_findfirst( Spec , 0xFF, &blk );
while( !done ) {
if( blk.attrib == FA_DIREC) {
if( blk.name[ 0 ] != '.' ) {
insertdirlist( p, &blk );
sprintf( temp, "%s\\%s", p, blk.name );
builddirlist( temp, s );
}
}
done = _dos_findnext( &blk );
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int scandir( char *pname, char *dname, char *args ) // look in the directory
{
char temp[ 128 ];
struct find_t blk;
sprintf( temp, "%s\\%s\\%s", pname, dname, args );
removedoubles( temp );
int done = _dos_findfirst( temp, 0xFF, &blk );
while( !done ) {
switch( blk.attrib ) {
case FA_RDONLY:
case FA_HIDDEN:
case FA_LABEL:
case FA_SYSTEM:
case 0x28:
case FA_DIREC:
break;
case FA_ARCH:
default:
sprintf( temp, "%s\\%s", pname, dname );
insertfilelist( temp, &blk );
break;
}
done = _dos_findnext( &blk );
}
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int buildfilelist( char *s ) // build a list of files
{
for( struct sFI *d = Rootdirs; d; d = d -> next ) {
scandir( d -> dirof, d -> blk.name, s );
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int driveexists( char *s ) // lazy programmer's way to see if a drive exists
{
unsigned current;
unsigned md;
unsigned t;
unsigned target = *s - 'A' + 1;
_dos_getdrive( ¤t );
_dos_setdrive( target, &md );
_dos_getdrive( &t );
_dos_setdrive( current, &md );
if( t == target ) {
return( 1 );
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
long dfs( char *s ) // just what it says <g>. disk free space.
{
struct diskfree_t free;
long avail;
clrscr();
gotoxy( 1, 1 ); printf( "Checking free space on %s", s );
int dnumber = *s - 'A' + 1;
if( _dos_getdiskfree( dnumber, &free ) != 0 ) {
return( 0 );
}
avail = (long)free.avail_clusters * (long)free.bytes_per_sector* (long) free.sectors_per_cluster;
gotoxy( 1, 1 ); printf( "%-4s reports %12ld bytes available", s, avail );
return( avail );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int parseargs( int argc, char *argv[] ) // the VERY lazy programmer's
{ // way to parse the command tail.
char allargs[ 128 ];
char *p;
/*
ARGV CONTENTS
--------------------
1 source specification (*.*, etc)
2 destination drive (a:, etc)
3 optional /s (re xcopy)
4 optional /z (use pkzip where possible)
*/
strcpy( allargs, "" );
for( int i = 1; i < argc; i++ ) {
strupr( argv[ i ] );
strcat( allargs, argv[ i ] );
}
if( strstr( allargs, "/S" ) )
Flag_subdirs = 1;
if( strstr( allargs, "/Z" ) ) {
if( searchpath( "PKZIP.COM" ) || searchpath( "PKZIP.EXE" ) ) {
Flag_usezip = 1;
} else {
printf( "Cannot find PKZIP.COM or PKZIP.EXE\n" );
return( 0 );
}
}
strcpy( Argv1, argv[ 1 ] );
strcpy( Argv2, argv[ 2 ] );
if( !driveexists( Argv2 ) ) {
printf( "Unable to locate destination drive %s\n", Argv2 );
return( 0 );
}
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int quit( void ) // hmmmm... I can't remember what this does...
{
chdir( Basecwd );
printf( "You are now in %s\n", Basecwd );
exit( 0 );
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
char drive[ 25 ];
char dir[ 128 ];
char name[ 25 ];
char ext[ 25 ];
char Dest[ 128 ];
int dothework( char *ddrive, struct sFI *s ) // here is where the work
{ // gets done...
if( Flag_usezip && !( strstr( s -> blk.name, ".ZIP" ) ) ) {
fnsplit( s -> blk.name, drive, dir, name, ext );
sprintf( Cmd, "pkzip -a %s%s.zip %s\\%s ", ddrive, name, s -> dirof, s -> blk.name, ddrive );
sprintf( Dest, "%s%s.ZIP", ddrive, name );
} else {
sprintf( Cmd, "xcopy %s\\%s %s", s -> dirof, s -> blk.name, ddrive );
sprintf( Dest, "%s%s", ddrive, s -> blk.name );
}
removedoubles( Cmd );
gotoxy( 1, 3 );printf( "%-79s\n", Cmd );
system( Cmd );
if( kbhit() ) {
return( 0 );
}
sprintf( Cmd, "copy %s NUL", Dest );
removedoubles( Cmd );
gotoxy( 1, 8 );printf( "%-79s\n", Cmd );
system( Cmd );
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int pl( void ) // select a file and copy it
{
while( more( &Total ) ) {
long df = dfs( Argv2 );
if( kbhit() ) {
break;
}
if( df == 0 ) {
break;
}
struct sFI *s = select( df );
if( s ) {
gotoxy( 1, 2 ); printf( "%-14s (%10ld) selected ", s -> blk.name, s -> blk.size );
s -> status[ 0 ] += dothework( Argv2, s );
}
}
return( 1 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/
int main( int argc, char *argv[] )
{
int m;
int ch;
clrscr();
getcwd( Basecwd, 128 );
if( argc < 3 ) {
printf( "OCOPY: a diskette optimizer\n" );
printf( "----------------------------\n" );
printf( "usage: ocop [spec] [dest] {options}\n\n" );
printf( " spec = source file specification\n" );
printf( " dest = destination drive\n" );
printf( " options\n" );
printf( " /S = include subdirectories\n" );
printf( " /Z = use PKZIP where appropriate\n\n\n" );
printf( "example: ocop *.* a: /S /Z\n" );
quit();
}
if( parseargs( argc, argv ) ) {
if( Flag_subdirs ) {
builddirlist( Basecwd, "*.*" );
buildfilelist( Argv1 );
}
scandir( Basecwd, "", Argv1 );
} else {
quit();
}
restart:
m = more( &Total );
long df = dfs( Argv2 );
if( m ) {
mtop:
clrscr();
drain();
printf( "There are yet %d files (%ld bytes) left to copy\n", m, Total );
printf( "There are %ld bytes left on %s\n", df, Argv2 );
printf( "Menu: \n" );
printf( "a. continue coping (i.e., %s is ready)\n", Argv2 );
printf( "d. perform a DIR on %s \n", Argv2 );
printf( "c. perform a chkdsk on %s\n", Argv2 );
printf( "e. erase the files on %s\n", Argv2 );
printf( "f. dothework the diskette in %s\n", Argv2 );
printf( "s. shell exit to dos\n", Argv2 );
printf( "w. walk the list of files\n" );
printf( "q. quit this program\n" );
drain();
ch = toupper( getch() );
clrscr();
switch( ch ) {
case 'A':
pl();
goto restart;
case 'C':
sprintf( Cmd, "chkdsk %s /f", Argv2 );
system( Cmd );
drain();
hitakey();
goto restart;
case 'D':
sprintf( Cmd, "DIR %s /p", Argv2 );
system( Cmd );
drain();
hitakey();
goto restart;
case 'E':
sprintf( Cmd, "erase %s*.*", Argv2 );
printf( "%s\n", Cmd );
system( Cmd );
drain();
hitakey();
goto restart;
case 'F':
sprintf( Cmd, "dothework %s /u", Argv2 );
system( Cmd );
drain();
hitakey();
goto restart;
case 'Q':
quit();
case 'S':
printf( "DOS doorway, type EXIT to return\n" );
system( "COMMAND" );
goto restart;
case 'W':
walkdriver();
goto restart;
default:
goto restart;
}
}
return( 0 );
}
/***************************************************************/
/* */
/* */
/* */
/* */
/***************************************************************/